#include "vty_ipc_msg.hpp"

void vty_ipc_msg::decode_msg(ipc_message& msg) 
{
    vty_ipc_hdr_t* hdr = (vty_ipc_hdr_t*)msg.body();
    decode_header(*hdr);
};

void vty_ipc_msg::encode_msg(ipc_message& msg) 
{
    vty_ipc_hdr_t* hdr = (vty_ipc_hdr_t*)msg.body();
    encode_header(*hdr);
};

int vty_ipc_msg::parse_msg(vty_ipc_message_t& msg, __u32& vty_id, __u32& cmd, 
        __u32& sub, string_vector& opts)
{
    int idx=0;
    std::size_t sum =0;
    const char* bptr = msg.body();
    vty_ipc_hdr_t* hdr = (vty_ipc_hdr_t*)msg.body();
    vty_ipc_opt_t opt;

    //msg.decode_header();  /* FIXME .... */
    
    if (sizeof(vty_ipc_hdr_t) > msg.body_length()) {
        return -1;
    }

    vty_id = hdr->_vty_id;
    cmd = hdr->_cmd;
    sub = hdr->_sub_cmd;

    if (hdr->_size == 0) return 0;

    bptr = msg.body() + sizeof(*hdr);

    std::string tmp;
    for (idx = 0; sum < hdr->_size; idx++) {
        memcpy(opt.data(), bptr, vty_ipc_opt_t::header_length);
        opt.decode_header();
        bptr += vty_ipc_opt_t::header_length;
        sum += vty_ipc_opt_t::header_length;
        tmp.assign(bptr, opt.body_length());
        bptr += opt.body_length();
        sum += opt.body_length();
        opts.push_back(tmp);
        PDBG("sum: %d, OPT: %s\n", (int)sum, tmp.c_str());
    }
    return idx;
}

void vty_ipc_msg::build_msg(__u32 vty_id, __u32 cmd, __u32 sub, 
        const string_vector& opts, vty_ipc_message_t& msg)
{
    this->build_msg(vty_id, (vty_cmd_t)cmd, (vty_sub_cmd_t)sub, opts, msg);
}

void vty_ipc_msg::build_msg(__u32 vty_id, vty_cmd_t cmd, vty_sub_cmd_t sub, 
            const string_vector& opts, vty_ipc_message_t& msg)
{
    char* dptr = msg.body();
    size_t offset=0, sum=0;
    vty_ipc_hdr_t hdr;

    dptr += sizeof(hdr);

    string_vector::const_iterator iter = opts.begin();
    for (; iter != opts.end(); iter++) {
        using namespace std; // For sprintf and memcpy.
        char header[ipc_message::header_length + 1] = "";
        offset = sprintf(header, "%4d", (int)(*iter).length());
        memcpy(dptr, header, ipc_message::header_length);
        dptr += offset;
        sum  += offset;
        memcpy(dptr, (*iter).c_str(), (*iter).length());
        dptr += (*iter).length();
        sum  += (*iter).length();
    }

    hdr._vty_id = vty_id;
    hdr._cmd = cmd;
    hdr._sub_cmd = sub;
    hdr._size = sum;
    memcpy(msg.body(), &hdr, sizeof(hdr));

    msg.body_length(sum + sizeof(hdr));
    msg.encode_header();
};


void vty_ipc_msg::decode_header(vty_msg_hdr_t& hdr)
{
    hdr._vty_id    = ntohl(hdr._vty_id);
    hdr._cmd       = ntohl(hdr._cmd);
    hdr._sub_cmd   = ntohl(hdr._sub_cmd);
    hdr._size  = ntohl(hdr._size);
    printf("ID: %d ",    hdr._vty_id);
    printf("CMD: %d ",   hdr._cmd);
    printf("SUB_CMD: %d ",   hdr._sub_cmd);
    printf("DATA LEN: %d \n",  hdr._size);
}

void vty_ipc_msg::encode_header(vty_msg_hdr_t& hdr)
{
    printf("ID: %d ",    hdr._vty_id);
    printf("CMD: %d ",   hdr._cmd);
    printf("SUB_CMD: %d ",   hdr._sub_cmd);
    printf("DATA LEN: %d \n",  hdr._size);
    hdr._vty_id    = htonl(hdr._vty_id);
    hdr._cmd       = htonl(hdr._cmd);
    hdr._sub_cmd   = htonl(hdr._sub_cmd);
    hdr._size  = htonl(hdr._size);
}


